package com.shunli.cterminal.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.examples.core.enums.*;
import com.examples.core.exception.ServiceException;
import com.examples.core.res.CommonResult;
import com.examples.core.res.PagingData;
import com.examples.core.tool.common.ConstDefine;
import com.examples.core.tool.constant.ExamplesConstants;
import com.examples.core.tool.utils.PagingHelper;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.shunli.cterminal.common.CommonConstants;
import com.shunli.cterminal.entity.*;
import com.shunli.cterminal.enums.*;
import com.shunli.cterminal.feign.AdPayService;
import com.shunli.cterminal.mapper.*;
import com.shunli.cterminal.mapstruct.SaleOrderAdTempConverter;
import com.shunli.cterminal.mapstruct.TempConverter;
import com.shunli.cterminal.model.ExtJson3;
import com.shunli.cterminal.model.bo.CalcResBO;
import com.shunli.cterminal.model.bo.PromotionConfigBO;
import com.shunli.cterminal.model.code.CterminalResultCode;
import com.shunli.cterminal.model.dto.*;
import com.shunli.cterminal.model.req.*;
import com.shunli.cterminal.model.res.*;
import com.shunli.cterminal.service.*;
import com.shunli.cterminal.util.AsyncUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @ClassName: OnlineOrderServiceImpl
 * @Description: TODO
 * @Author: DAIYALU
 * @Date: 2024/10/25
 * @Version: 1.0
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class OnlineOrderServiceImpl implements OnlineOrderService {

    private final TempConverter tempConverter = TempConverter.INSTANCE;
    private final SaleOrderAdTempConverter adTempConverter = SaleOrderAdTempConverter.INSTANCE;

    private final PromotionConfigMapper promotionConfigMapper;
    private final SystemOrderAdTempMapper adTempMapper;
    private final SystemOrderPayFlowMapper orderPayFlowMapper;
    private final SystemTradeOnlineConfigMapper tradeOnlineConfigMapper;
    private final SystemGoodsManageMapper goodsManageMapper;
    private final SystemMallPlatformMapper mallPlatformMapper;
    private final SystemGoodsChannelMapper goodsChannelMapper;
    private final MiddleBusinessMapper middleBusinessMapper;
    private final SystemOrderMapper orderMapper;
    private final SystemBizTemplateMapper systemBizTemplateMapper;
    private final SystemShipChannelLinkMapper channelLinkMapper;
    private final TemplateService templateService;
    private final ShipWayService shipWayService;
    private final OrderNoService orderNoService;
    private final CommonServiceImpl commonService;
    private final OrderDataEtlService orderDataEtlService;
    private final RedissonClient redissonClient;
    private final AdPayService adPayService;
    private final AbTestService abTestService;
    private final StringRedisTemplate redisTemplate;
    private final ISystemTrafficPolicyService systemTrafficPolicyService;
    private final ResultRedEnvelopeService redEnvelopeService;

    @Override
    public OrderAndTempConfig getAdOrderAndTempConfig(H5TempInfoReq req) {
        log.info("getAdOrderAndTempConfig[] 获取订单和模板信息入参, req:{}", JSON.toJSONString(req));
        //子线程获取订单信息
        CompletableFuture<H5OrderInfoVO> orderFuture = null;
        if (StringUtils.isNotBlank(req.getOrderId())){
            //查询订单信息
            orderFuture = AsyncUtils.supplyAsync(() -> queryOrder(req.getOrderId()));
            //生成支付链接
            prePay(req);
        }
        //获取模板ID
        getTemplateId(req);
        //获取缓存模板信息
        String businessKey = StringUtils.isNotBlank(req.getOrderId())? CommonConstants.PAY : CommonConstants.LANDING;
        String key = businessKey + StringPool.COLON + Optional.ofNullable(req.getPromotionCode()).orElse(req.getDomainName());
        RMap<String,OrderAndTempConfig> rBucket = redissonClient.getMap(CommonConstants.NEW_BIZ_TEMPLATE_MAP_CACHE_KEY + req.getTemplateId());
        OrderAndTempConfig orderAndTempConfig = rBucket.get(key);
        log.info("getAdOrderAndTempConfig从缓存获取的模板信息：{}", JSON.toJSONString(orderAndTempConfig));
        //缓存为空查询数据
        if(Objects.isNull(orderAndTempConfig)){
            //模板信息
            CompletableFuture<GoodsTemplateVO> templateFuture = AsyncUtils.supplyAsync(() -> getTemplateInfo(req));
            //主体公司信息
            CompletableFuture<CompanyInfo> companyFuture = AsyncUtils.supplyAsync(() -> promotionConfigMapper.queryCompanyInfoByDomain(req.getDomainName()));
            CompletableFuture.allOf(companyFuture,templateFuture).join();
            CompanyInfo companyInfo = companyFuture.join();
            GoodsTemplateVO templateVo = templateFuture.join();
            orderAndTempConfig = tempConverter.tempConfigConverter(templateVo);
            orderAndTempConfig.setCompany(companyInfo);
            for (TemplateDetailVO detail : templateVo.getDetails()) {
                if (StringUtils.isBlank(req.getOrderId())){
                    if (BizTemplateStyleEnum.LANDING.getCode().equals(detail.getCode())){
                        orderAndTempConfig.setColor(detail.getColor());
                        orderAndTempConfig.setContent(detail.getStyleInfo());
                    }
                }else if (BizTemplateStyleEnum.PAY.getCode().equals(detail.getCode())){
                    orderAndTempConfig.setColor(detail.getColor());
                    orderAndTempConfig.setContent(detail.getStyleInfo());
                }
            }
            orderAndTempConfig.setTempId(req.getTemplateId());
            log.info("getAdOrderAndTempConfig保存至缓存的模板信息：{}", JSON.toJSONString(orderAndTempConfig));
            //缓存模板信息
            rBucket.put(key,orderAndTempConfig);
        }
        //用户IP
        orderAndTempConfig.setUserIp(req.getUserIp());
        //补充订单信息
        if (StringUtils.isNotEmpty(req.getOrderId()) && Objects.nonNull(orderFuture)){
            H5OrderInfoVO orderInfoVO = orderFuture.join();
            orderAndTempConfig.setOrder(tempConverter.adOrderConverter(orderInfoVO));
        }
        return orderAndTempConfig;
    }

    @Override
    public H5OrderOptVO create(H5OrderCrtReq req) {
        log.info("create, req:{}", JSONUtil.toJsonStr(req));
        TfGoodsCodeEnum codeEnum = TfGoodsCodeEnum.ofCodeNoisy(req.getGoodsType());
        validateOrderCrtParams(req,codeEnum);
        TgChannel tgChannel = new TgChannel();
        if(StrUtil.isNotBlank(req.getTgPar())){
            tgChannel = JSONUtil.toBean(req.getTgPar(), TgChannel.class);
        }
        SystemGoodsManage goodsManage = goodsManageMapper.selectOne(Wrappers.<SystemGoodsManage>lambdaQuery()
                .eq(SystemGoodsManage::getSkuId, req.getGoodsType())
                .eq(SystemGoodsManage::getStatus, CommonStatusEnum.ENABLE.getCode())
                .select(SystemGoodsManage::getId,SystemGoodsManage::getName,SystemGoodsManage::getSkuId)
                .last(ExamplesConstants.EXAM_MYSQL_LIMIT));
        log.info("create, goodsManage:{}", goodsManage);
        if(null == goodsManage){
            throw new ServiceException(CterminalResultCode.H5_GOODS_NOT_EXIST);
        }
        String mallCode = OrderMallEnum.AD.getCode();
        // 查询推广信息
        List<PromotionConfigBO> promotionSelectVoList = promotionConfigMapper.queryPromotionConfigList(req.getDomainName(),req.getGoodsType(),tgChannel.getChannel());
        log.info("create, promotionSelectVoList:{}", JSONUtil.toJsonStr(promotionSelectVoList));
        PromotionConfigBO promotionSelectVo = null;
        //修改 落地页返回商城下其他商品的订单 没有匹配到推广信息的问题
        if(CollectionUtil.isNotEmpty(promotionSelectVoList)){
            // 优先匹配想同商品编码的推广信息
            for (PromotionConfigBO selectVo : promotionSelectVoList) {
                if(StrUtil.equals(req.getGoodsType(),  selectVo.getSkuId())){
                    promotionSelectVo = selectVo;
                    log.info("create命中关联商品推广信息配置：{}", JSONUtil.toJsonStr(promotionSelectVo));
                    break;
                }
            }
            if(ObjectUtil.isNull(promotionSelectVo)){
                promotionSelectVo = promotionSelectVoList.get(0);
                log.info("create未命中推广信息配置，默认兜底：{}", JSONUtil.toJsonStr(promotionSelectVo));
            }
        }
        BigDecimal realAmount = BigDecimal.ZERO;
        if(null != promotionSelectVo){
            realAmount = Optional.ofNullable(promotionSelectVo.getPrice()).orElse(BigDecimal.ZERO);
        }else{// 自然流量
            promotionSelectVo = new PromotionConfigBO();
        }
        // 查询商城信息(媒体)
        if(StrUtil.isNotBlank(promotionSelectVo.getPlatform())){
            SystemMallPlatform mallPlatform = mallPlatformMapper.selectOne(Wrappers.<SystemMallPlatform>lambdaQuery()
                    .eq(SystemMallPlatform::getPlatformCode, promotionSelectVo.getPlatform())
                    .select(SystemMallPlatform::getId,SystemMallPlatform::getMallCode)
                    .last(ExamplesConstants.EXAM_MYSQL_LIMIT));
            log.info("create, mallPlatform:{}", mallPlatform);
            if(null != mallPlatform){
                mallCode = mallPlatform.getMallCode();
            }
        }

        // 如果是推广测试，金额为0.01
        if(StrUtil.isNotBlank(tgChannel.getState()) && StrUtil.isNotBlank(promotionSelectVo.getTgTestCode()) && tgChannel.getState().equals(promotionSelectVo.getTgTestCode())){
            realAmount = BigDecimal.valueOf(0.01);
        }
        SystemGoodsChannel goodsChannel = this.queryMallGoodsByMallCodeAndGoodsId(goodsManage.getId(),mallCode);
        log.info("create, goodsChannel:{}", goodsChannel);

        BigDecimal yuanPrice = Optional.ofNullable(goodsChannel.getDisplayPrice()).orElse(BigDecimal.ZERO);
        if(BigDecimal.ZERO.compareTo(realAmount) == 0){
            realAmount = Optional.ofNullable(goodsChannel.getSellingPrice()).orElse(yuanPrice);
        }

        TrafficPolicyStrategyDTO trafficPolicyStrategyDTO = new TrafficPolicyStrategyDTO();
        trafficPolicyStrategyDTO.setPlatform(promotionSelectVo.getPlatform());
        trafficPolicyStrategyDTO.setGoodsId(promotionSelectVo.getGoodsId());
        trafficPolicyStrategyDTO.setRealAmount(realAmount);
        trafficPolicyStrategyDTO.setPromotionCode(tgChannel.getChannel());
        trafficPolicyStrategyDTO.setCreateOrderTime(LocalDateTime.now());
        String projectCode = systemTrafficPolicyService.parse(trafficPolicyStrategyDTO,null);
        promotionSelectVo.setMallCode(mallCode);
        promotionSelectVo.setProjectCode(projectCode);
        promotionSelectVo.setGoodsId(goodsManage.getId().toString());
        promotionSelectVo.setGoodsName(goodsManage.getName());

        // 获取发货方式
        LinkQueryReq linkReq = new LinkQueryReq();
        linkReq.setGoodsId(goodsManage.getId());
        linkReq.setProductType(codeEnum.getTwoEnum().getOneEnum().getCode());
        buildShipProjectCode(linkReq,promotionSelectVo);
        JumpLinkVO linkVO = shipWayService.queryLink(linkReq);
        log.info("create, linkVO:{}", JSONUtil.toJsonStr(linkVO));
        if(null == linkVO){
            linkVO = new JumpLinkVO();
        }
        SystemOrderAdTemp adTemp = this.buildOrderAdTemp(req,yuanPrice,realAmount,promotionSelectVo,linkVO,codeEnum);
        log.info("create, adTemp:{}", adTemp);
        adTempMapper.insert(adTemp);
        AsyncUtils.runAsync(()->{
            //推送未支付订单到投放系统
            return pushOrderDataToAd(adTemp);
        });
        H5OrderOptVO vo = new H5OrderOptVO();
        vo.setOrderId(adTemp.getEncryptionOrder());
        vo.setGoodsName(adTemp.getGoodsName());
        vo.setPayDomain(adTemp.getPayDomain());
        return vo;
    }

    @Override
    public H5OrderOptVO useRedBag(H5OrderUseRedBagReq req) {
        SystemOrderAdTemp adTemp = adTempMapper.selectOne(Wrappers.<SystemOrderAdTemp>lambdaQuery()
                .eq(SystemOrderAdTemp::getEncryptionOrder, req.getOrderId())
                .last(ExamplesConstants.EXAM_MYSQL_LIMIT));
        log.info("useRedBag, adTemp:{}", adTemp);
        if(null == adTemp){
            throw new ServiceException(CterminalResultCode.H5_ORDER_NOT_EXIST);
        }
        BigDecimal redBagAmount = Optional.ofNullable(adTemp.getAbductBao()).orElse(BigDecimal.ZERO);
        if(!ConstDefine.C_COMMON.INTEGER_ZERO.equals(adTemp.getIsUseRedbag()) || redBagAmount.compareTo(BigDecimal.ZERO) > 0){
            throw new ServiceException(CterminalResultCode.H5_RED_BAG_USED);
        }
        // 已经支付过了，不能在使用红包
        Integer state = Optional.ofNullable(adTemp.getState()).orElse(ConstDefine.C_COMMON.INTEGER_ZERO);
        if(ConstDefine.C_COMMON.INTEGER_ONE.equals(state)){
            throw new ServiceException(CterminalResultCode.H5_ORDER_PAYED);
        }
        // 查询红包金额
        BigDecimal redEnvelopeAmount = redEnvelopeService.getRedEnvelopeAmount(adTemp.getRealAmount());
        log.info("useRedBag, redEnvelopeAmount:{}", redEnvelopeAmount);
        if(BigDecimal.ZERO.compareTo(redEnvelopeAmount) == 0){
            throw new ServiceException(CterminalResultCode.H5_RED_BAG_AMOUNT_ERROR);
        }
        if(BigDecimal.ZERO.compareTo(adTemp.getRealAmount()) > 0){
            throw new ServiceException(CterminalResultCode.H5_RED_BAG_AMOUNT_ERROR);
        }
        adTemp.setAbductBao(redEnvelopeAmount);
        adTemp.setIsUseRedbag(ConstDefine.C_COMMON.INTEGER_ONE);
        adTemp.setRealAmount(adTemp.getRealAmount().subtract(redEnvelopeAmount));
        if(BigDecimal.ZERO.compareTo(adTemp.getRealAmount()) > 0){
            throw new ServiceException(CterminalResultCode.H5_RED_BAG_AMOUNT_ERROR);
        }
//        adTemp.setEncryptionOrder(Optional.ofNullable(adTemp.getOrderFname()).orElse(StringPool.EMPTY).concat(this.queryOrderNo()));
        adTemp.setPayUrl(null);
        adTempMapper.updateById(adTemp);
        H5OrderOptVO vo = new H5OrderOptVO();
        vo.setOrderId(adTemp.getEncryptionOrder());
        vo.setGoodsName(adTemp.getGoodsName());
        log.info("useRedBag, adTemp:{}", adTemp);
        //推送未支付订单到投放系统
        this.pushOrderDataToAd(adTemp);
        return vo;
    }

    @Override
    public PagingData<MyOrderInfoVO> myOrder(MyOrderQueryReq req) {
        if(StrUtil.isBlank(req.getPhone()) && StrUtil.isBlank(req.getOrderId())){
            req.setId(ConstDefine.C_COMMON.LONG_ZERO);
        }
        if (Objects.nonNull(req.getMinId())){
            req.setPageNum(1);
        }
        log.info("myOrder[] 查询我的订单入参 req:{}", JSON.toJSONString(req));
        Page<MyOrderInfoVO> page = new Page<MyOrderInfoVO>(req.getPageNum(), req.getPageSize());
        long start = System.currentTimeMillis();
        IPage<MyOrderInfoVO> result = adTempMapper.queryMyOrderList(req,page);
        log.info("myOrder[] 查询我的订单耗时:{}",System.currentTimeMillis() - start);
        PagingData<MyOrderInfoVO> voPagingData = PagingHelper.fromMyBatisPlusPage(result);
        List<MyOrderInfoVO> voList = voPagingData.getList();
        if (CollectionUtil.isEmpty(voList)){
            log.info("myOrder[] 查询我的订单结果 voPagingData:{}", JSON.toJSONString(voPagingData));
            return voPagingData;
        }
        List<String> goodsCodeList = voList.stream().map(MyOrderInfoVO::getGoodsType).filter(Objects::nonNull).collect(Collectors.toList());
        Map<String, CalcResBO> boMap = Maps.newHashMap();
        if(CollectionUtil.isNotEmpty(goodsCodeList)){
            List<CalcResBO> boList = middleBusinessMapper.queryCalcRes(goodsCodeList);
            if(CollectionUtil.isNotEmpty(boList)){
                boMap = boList.stream().collect(Collectors.toMap(CalcResBO::getGoodsCode,bo -> bo,(k1,k2)->k2));
            }
        }
        boMap.forEach((k,v) ->{
            ReqProtocolEnum protocolEnum = ReqProtocolEnum.ofCodeNoisy(v.getIsSsl());
            StringBuilder sb = new StringBuilder();
            sb.append(protocolEnum.getDesc())
                    .append(StringPool.COLON)
                    .append(StringPool.SLASH).append(StringPool.SLASH)
                    .append(v.getDomain())
                    .append(StringPool.SLASH)
                    .append(v.getPath());
            v.setLink(sb.toString());
        });
        for (MyOrderInfoVO vo : voList) {
            if(StrUtil.isNotBlank(vo.getTgPar())){
                try{
                    TgChannel tgChannel = JSONUtil.toBean(vo.getTgPar(), TgChannel.class);
                    vo.setChannel(tgChannel.getChannel());
                }catch (Exception e){
                    log.info("【订单】解析推广参数失败，订单号：{}，推广参数：{}",vo.getOrderId(),vo.getTgPar());
                }
            }
            if(!boMap.containsKey(vo.getGoodsType())){
                continue;
            }
            vo.setLink(boMap.get(vo.getGoodsType()).getLink() + vo.getOrderId());
        }
        log.info("myOrder[] 查询我的订单接口总耗时:{}",System.currentTimeMillis() - start);
        return voPagingData;
    }

    @Override
    public String viewResPage(ViewResPageReq req) {
        SystemOrder order = orderMapper.queryInfoByOrderNo(req.getOrderId());
        if(null == order){
            return req.getOrderId();
        }
        if(OrderShipStatusEnum.SHIPPED.getCode().equals(order.getShipStatus())){
            Boolean updateFlag = Boolean.FALSE;
            LambdaUpdateWrapper<SystemOrder> update = new LambdaUpdateWrapper<SystemOrder>();
            if(OrderV2StatusEnum.PAID.getCode().equals(order.getStatus())){
                update.set(SystemOrder::getStatus,OrderV2StatusEnum.COMPLETED.getCode());
                updateFlag = Boolean.TRUE;
            }
            if(null == order.getSignOnTime()){
                update.set(SystemOrder::getSignOnTime,LocalDateTime.now());
                updateFlag = Boolean.TRUE;
            }
            if(updateFlag){
                update.eq(SystemOrder::getOrderNo,req.getOrderId());
                orderMapper.update(update);
            }
        }
        return req.getOrderId();
    }

    @Override
    public QueryAdOrderVO queryAdOrder(String orderId){
        if(StringUtils.isBlank(orderId)){
            return null;
        }
        SystemOrderAdTemp adTemp = adTempMapper.selectOne(Wrappers.<SystemOrderAdTemp>lambdaQuery()
                .eq(SystemOrderAdTemp::getEncryptionOrder, orderId)
                .last(ExamplesConstants.EXAM_MYSQL_LIMIT));
        if(null == adTemp){
            throw new ServiceException(CterminalResultCode.H5_ORDER_NOT_EXIST);
        }
        QueryAdOrderVO resp = new QueryAdOrderVO();
        resp.setOrderId(adTemp.getEncryptionOrder());
        resp.setUid(adTemp.getUid());
        resp.setGoodsType(adTemp.getGoodsCode());
        resp.setDomainName(adTemp.getUrlName());
        return resp;
    }

    @Override
    public PayedOrderInfoVO getPayedOrderInfo(String orderId) {
        log.info("getPayedOrderInfo, orderId:{}", orderId);
        PayedOrderInfoVO vo = null;
        try {
            if(Objects.isNull(orderId)){
                throw new ServiceException(CterminalResultCode.PARAMS_EMPTY);
            }
            SystemOrderAdTemp adTemp = adTempMapper.selectOne(Wrappers.<SystemOrderAdTemp>lambdaQuery()
                    .eq(SystemOrderAdTemp::getEncryptionOrder, orderId)
                    .last(ExamplesConstants.EXAM_MYSQL_LIMIT));
            log.info("getPayedOrderInfo, adTemp:{}", adTemp);

            if(null == adTemp){
                throw new ServiceException(CterminalResultCode.H5_ORDER_NOT_EXIST);
            }
            vo = adTempConverter.adTempToPayedOrderInfo(adTemp);
            vo.setGoodsType(adTemp.getGoodsCode());
            vo.setIsLunar(adTemp.getBirthdayType());
            vo.setExistPhone(Boolean.FALSE);
            if(StrUtil.isNotBlank(adTemp.getPhone())
                    || StrUtil.isNotBlank(adTemp.getEmail())){
                vo.setExistPhone(Boolean.TRUE);
            }

            vo.setOrderId(adTemp.getEncryptionOrder());
            vo.setBottom(new Bottom());
            if(adTemp.getState() == 1){
                if(FhTypeEnum.AUTO.getCode().equals(vo.getFhType())){
                    List<CalcResBO> boList = middleBusinessMapper.queryCalcRes(List.of(vo.getGoodsType()));
                    log.info("getPayedOrderInfo, boList:{}", JSONUtil.toJsonStr(boList));

                    if(CollectionUtil.isNotEmpty(boList)){
                        CalcResBO bo = boList.get(0);
                        ReqProtocolEnum protocolEnum = ReqProtocolEnum.ofCodeNoisy(bo.getIsSsl());
                        StringBuilder sb = new StringBuilder();
                        sb.append(protocolEnum.getDesc())
                                .append(StringPool.COLON)
                                .append(StringPool.SLASH).append(StringPool.SLASH)
                                .append(bo.getDomain())
                                .append(StringPool.SLASH)
                                .append(bo.getPath())
                                .append(vo.getOrderId());
                        vo.setLink(sb.toString());
                    }
                }else{
                    vo.setLink(this.queryLinkResult(null,adTemp));
                    vo.setResultLink(vo.getLink());
                }
            }
            if(StrUtil.isNotBlank(adTemp.getExtJson())){
                OrderExtJson extJson = JSONUtil.toBean(adTemp.getExtJson(), OrderExtJson.class);
                TfGoodsCodeEnum codeEnum = TfGoodsCodeEnum.ofCodeNoisy(adTemp.getGoodsCode());
                if(TfGoodsCodeEnum.BAOBAOQIMING.equals(codeEnum)){
                    vo.setIsBirth(extJson.getIsBirth());
                }else{
                    vo.setBusinessType(extJson.getBusinessType());
                    vo.setAreaFname(extJson.getAreaFname());
                    vo.setHangyeLname(extJson.getHangyeLname());
                }
            }
        }catch (Exception e){
            log.info("getPayedOrderInfo error case:{}", Throwables.getStackTraceAsString(e));
        }
        return vo;
    }

    public String queryLinkResult(String orderNo,SystemOrderAdTemp adTemp) {
        if(null == adTemp){
            adTemp = adTempMapper.selectOne(Wrappers.<SystemOrderAdTemp>lambdaQuery().eq(SystemOrderAdTemp::getEncryptionOrder, orderNo));
        }
        log.info("queryLinkResult, adTemp:{}", adTemp);

        if (null == adTemp) {
            return StringPool.EMPTY;
        }
        String resultLink = Optional.ofNullable(adTemp.getResultLink()).orElse(StringPool.EMPTY);
        String goodsCode = adTemp.getGoodsCode();
        try{
            // 易启创链接从php获取 没有的话就直接返回空
            if(OrderBelongsEnum.YQC.getCode().equals(adTemp.getBelongs())){
                return StrUtil.blankToDefault(adTemp.getResultLink(),"");
            }

            TfGoodsCodeEnum goodsCodeEnum = TfGoodsCodeEnum.ofCodeNoisy(goodsCode);
            String productType = goodsCodeEnum.getTwoEnum().getOneEnum().getCode();
            String jumpWay = adTemp.getFhType();
            SystemShipChannelLink channelLink = null;
            if (StrUtil.isNotBlank(resultLink)) {
                channelLink = channelLinkMapper.selectOne(Wrappers.<SystemShipChannelLink>lambdaQuery()
                        .eq(SystemShipChannelLink::getStatus, CommonStatusEnum.ENABLE.getCode())
                        .eq(SystemShipChannelLink::getLink, resultLink));
                if(null != channelLink){
                    return resultLink;
                }
            }
            jumpWay = FhTypeEnum.WECHAT.getCode().equals(jumpWay) ? JumpWayEnum.WECHAT_CUSTOMER.getCode() : jumpWay;
            SystemOrder systemOrder = orderMapper.queryOrderByOrderNo(adTemp.getEncryptionOrder());
            String projectCode = ProjectCodeEnum.processProject(ProjectCodeEnum.GX.getCode(),systemOrder.getProjectCode());
            String channelType = ShipChannelTypeEnum.ADV.getCode();
            if (StringUtils.isNotEmpty(systemOrder.getAdChannelCode()) && !StringUtils.startsWith(systemOrder.getAdChannelCode(), "ggtf")) {
                channelType = ShipChannelTypeEnum.DY.getCode();
            }
            channelLink = channelLinkMapper.selectOne(Wrappers.<SystemShipChannelLink>lambdaQuery()
                    .eq(SystemShipChannelLink::getStatus, CommonStatusEnum.ENABLE.getCode())
                    .eq(SystemShipChannelLink::getProductType, productType)
                    .eq(SystemShipChannelLink::getJumpWay, jumpWay)
                    .eq(SystemShipChannelLink::getProjectCode, projectCode)
                    .eq(SystemShipChannelLink::getChannelType, channelType)
                    .last(ExamplesConstants.EXAM_MYSQL_LIMIT));
            log.info("queryLinkResult, channelLink:{}", channelLink);

            if(null == channelLink) {
                return StringPool.EMPTY;
            }
            resultLink = channelLink.getLink();
            channelLink.setLink(resultLink);
            channelLink.setSaleWxCustomerAcquisitionId(channelLink.getSaleWxCustomerAcquisitionId());
            adTempMapper.updateById(adTemp);
        }catch (Exception e){
            log.error("获取发货链接失败，订单号：{}",orderNo);
        }
        return resultLink;
    }

    private SystemOrderAdTemp buildOrderAdTemp(H5OrderCrtReq req, BigDecimal yuanPrice, BigDecimal realAmount, PromotionConfigBO vo, JumpLinkVO linkVO, TfGoodsCodeEnum codeEnum){
        // state 数据库默认未支付
        SystemOrderAdTemp adTemp = new SystemOrderAdTemp();
        adTemp.setUid(req.getUid());
        adTemp.setPhone(req.getPhone());
        adTemp.setGoodsCode(req.getGoodsType());
        adTemp.setOrderFname(codeEnum.getOrderFname());
        adTemp.setEncryptionOrder(Optional.ofNullable(adTemp.getOrderFname()).orElse(StringPool.EMPTY).concat(orderNoService.queryOrderNo()));
        adTemp.setFirstName(req.getFirstName());
        adTemp.setUserName(StrUtil.blankToDefault(req.getUserName(),req.getWoName()));
        adTemp.setWoName(req.getWoName());
        adTemp.setTaName(req.getTaName());
        adTemp.setWbirthday(req.getWbirthday());
        adTemp.setTbirthday(req.getTbirthday());
        adTemp.setSex(req.getSex());
        adTemp.setBirthday(req.getBirthday());
        adTemp.setBirthdayType(req.getIsLunar());
        adTemp.setRealAmount(realAmount);
        adTemp.setCreateTime(LocalDateTime.now());
        adTemp.setUrlName(req.getDomainName());
        adTemp.setUserIp(req.getUserIp());
        adTemp.setSystem(req.getSystem());
        if(StrUtil.equals(linkVO.getJumpFlag(),JumpFlagEnum.AUTO_JUMP.getCode())){
            adTemp.setFhType(FhTypeEnum.AUTO.getCode());
        } else {
            adTemp.setFhType(JumpWayEnum.WECHAT_CUSTOMER.getCode().equals(linkVO.getShipWay()) ? FhTypeEnum.WECHAT.getCode() : linkVO.getShipWay());
        }
        adTemp.setResultLink(linkVO.getLink());
        adTemp.setSaleWxCustomerAcquisitionId(linkVO.getSaleWxCustomerAcquisitionId());
        adTemp.setTgAccountId(vo.getAccountId());
        adTemp.setTsUserId(vo.getTsUserId());
        adTemp.setTgId(null != vo.getId() ? vo.getId().intValue() : null);
        adTemp.setTgPar(req.getTgPar());
        adTemp.setTgTemp(req.getTgTemp());
        adTemp.setUserAddress(commonService.resolveIp(req.getUserIp()));
        adTemp.setTgPlat(vo.getPlatform());
        adTemp.setGoodsId(vo.getGoodsId());
        adTemp.setGoodsName(vo.getGoodsName());
        adTemp.setYuanPrice(yuanPrice);
        if(TfGoodsCodeEnum.BAOBAOQIMING.equals(codeEnum)){
            Map<String,String> extJson = Maps.newHashMap();
            extJson.put("isBirth",req.getIsBirth());
            adTemp.setExtJson(JSONUtil.toJsonStr(extJson));
        }
        if(TfGoodsCodeEnum.GONGSIQIMING.equals(codeEnum)){
            Map<String,String> extJson = Maps.newHashMap();
            extJson.put("businessType",req.getBusinessType());
            extJson.put("areaFname",req.getAreaFname());
            extJson.put("hangyeLname",req.getHangyeLname());
            adTemp.setExtJson(JSONUtil.toJsonStr(extJson));
        }
        ExtJson3 extJson3 = new ExtJson3();
        extJson3.setMallCode(vo.getMallCode());
        extJson3.setProjectCode(vo.getProjectCode());
        extJson3.setPlatformCode(vo.getPlatform());
        adTemp.setExtJson3(JSONUtil.toJsonStr(extJson3));
        //获取支付域名
        long start = System.currentTimeMillis();
        CommonResult<MerchantDTO> result = adPayService.getPayDomain(vo.getMallCode(), vo.getProjectCode());
        log.info("getPayDomain[] time:{},result:{}",System.currentTimeMillis() - start,JSON.toJSONString(result));
        if (result.isSuccess() && Objects.nonNull(result.getData())){
            MerchantDTO merchantDTO = result.getData();
            adTemp.setPayDomain(merchantDTO.getPayDomain());
            adTemp.setExtJson2(JSON.toJSONString(merchantDTO));
        }
        return adTemp;
    }

    private void buildShipProjectCode(LinkQueryReq linkReq, PromotionConfigBO trafficDomainVO) {
        try {
            String projectCode = ProjectCodeEnum.processProject(ProjectCodeEnum.GX.getCode(),trafficDomainVO.getProjectCode());
            String channelType = ShipChannelTypeEnum.ADV.getCode();
            if (StringUtils.isNotEmpty(trafficDomainVO.getPromotionChannel())
                    && !StringUtils.startsWith(trafficDomainVO.getPromotionChannel(), "ggtf")) {
                channelType = ShipChannelTypeEnum.DY.getCode();
            }
            linkReq.setProjectCode(projectCode);
            linkReq.setChannelType(channelType);
            log.info("buildShipProjectCode,{},{}", JSONUtil.toJsonStr(linkReq), JSONUtil.toJsonStr(trafficDomainVO));
        } catch (Exception e) {
            log.error("buildShipProjectCode,e,{}", e);
        }
    }

    private boolean pushOrderDataToAd(SystemOrderAdTemp adTemp){
        try{
            PushOrderReq pushReq = new PushOrderReq();
            pushReq.setOrderNo(adTemp.getEncryptionOrder());
            TgChannel tgChannel = new TgChannel();
            if(StrUtil.isNotBlank(adTemp.getTgPar())){
                tgChannel = JSONUtil.toBean(adTemp.getTgPar(), TgChannel.class);
            }
            log.info("pushOrderDataToAd, adTemp:{}, pushReq:{}", adTemp, pushReq);
            pushReq.setAdChannelCode(tgChannel.getChannel());
            orderDataEtlService.orderDataHandler(adTemp,pushReq);
        }catch (Exception e){
            log.error("【推送订单】推送订单给到投放系统失败，订单号：{}",adTemp.getEncryptionOrder());
        }
        return true;
    }

    /**
     * 查询商城商品信息
     * @param goodsId 商品ID
     * @param mallCode 商城编码
     * @return
     */
    private SystemGoodsChannel queryMallGoodsByMallCodeAndGoodsId(Long goodsId,String mallCode){
        List<SystemGoodsChannel> goodsChannelList = goodsChannelMapper.selectList(Wrappers.<SystemGoodsChannel>lambdaQuery()
                .eq(SystemGoodsChannel::getGoodsId, goodsId)
                .in(SystemGoodsChannel::getMallCode, List.of(mallCode, OrderMallEnum.AD.getCode()))
                .eq(SystemGoodsChannel::getStatus, CommonStatusEnum.ENABLE.getCode())
                .last(ExamplesConstants.EXAM_MYSQL_LIMIT));
        if(CollectionUtil.isEmpty(goodsChannelList)){
            throw new ServiceException(CterminalResultCode.H5_GOODS_NOT_EXIST);
        }
        SystemGoodsChannel goodsChannel = null;
        for (SystemGoodsChannel goods : goodsChannelList) {
            if(mallCode.equals(goods.getMallCode())){
                goodsChannel = goods;
                break;
            }
        }
        if(null == goodsChannel){
            goodsChannel = goodsChannelList.stream().filter(goods -> OrderMallEnum.AD.getCode().equals(goods.getMallCode())).findFirst().orElse(null);
        }
        if(null == goodsChannel){
            throw new ServiceException(CterminalResultCode.H5_GOODS_NOT_EXIST);
        }
        return goodsChannel;
    }

    public static void validateOrderCrtParams(H5OrderCrtReq req,TfGoodsCodeEnum codeEnum){
        if(TfGoodsCodeTwoEnum.YUNSHI.equals(codeEnum.getTwoEnum())){
            if(StrUtil.isBlank(req.getUserName()) || null == req.getSex() || null == req.getBirthday()){
                throw new ServiceException(CterminalResultCode.PARAMS_EMPTY);
            }
        }
        if(TfGoodsCodeTwoEnum.YINYUAN.equals(codeEnum.getTwoEnum())){
            if(TfGoodsCodeEnum.BAZIHEHUN.equals(codeEnum)){
                if(StrUtil.isBlank(req.getWoName()) || StrUtil.isBlank(req.getTaName()) || null == req.getWbirthday() || null == req.getTbirthday() || null == req.getSex()){
                    throw new ServiceException(CterminalResultCode.PARAMS_EMPTY);
                }
            }
            if(TfGoodsCodeEnum.ZHENGYUANHX.equals(codeEnum)){
                if(StrUtil.isBlank(req.getWoName()) || null == req.getSex() || null == req.getWbirthday()){
                    throw new ServiceException(CterminalResultCode.PARAMS_EMPTY);
                }
            }
        }
        if(TfGoodsCodeTwoEnum.BAOBAO.equals(codeEnum.getTwoEnum())){
            if(StrUtil.isBlank(req.getFirstName()) || null == req.getSex() || null == req.getBirthday() || StrUtil.isBlank(req.getIsBirth())){
                throw new ServiceException(CterminalResultCode.PARAMS_EMPTY);
            }
        }
        if(TfGoodsCodeTwoEnum.GONGSI.equals(codeEnum.getTwoEnum())){
            if(StrUtil.isBlank(req.getUserName()) || null == req.getSex() || null == req.getBirthday() || StrUtil.isBlank(req.getBusinessType())
                    || StrUtil.isBlank(req.getAreaFname()) || StrUtil.isBlank(req.getHangyeLname())){
                throw new ServiceException(CterminalResultCode.PARAMS_EMPTY);
            }
        }
    }

    private void getTemplateId(H5TempInfoReq req){
        log.info("getAdOrderAndTempConfig[] 查询广告订单和模板信息, req:{}", JSON.toJSONString(req));
        try {
            Long templateIdByABTest = this.getTemplateIdByABTestFilter(req);
            if (ObjectUtil.isNotNull(templateIdByABTest)) {
                req.setTemplateId(templateIdByABTest);
                return;
            }
        } catch (Exception e) {
            log.info("getAdOrderAndTempConfig通过AB查询模板ID失败, msg:{}", e.getMessage(), e);
        }

        //订单模板
        if (StringUtils.isNotBlank(req.getOrderId())){
            List<SystemOrderAdTemp> systemOrderAdTemps = adTempMapper.queryTempByOrderNo(req.getOrderId());
            log.info("getAdOrderAndTempConfig[] 查询广告订单和模板信息-订单号, systemOrderAdTemps:{}", JSON.toJSONString(systemOrderAdTemps));
            if (CollectionUtil.isNotEmpty(systemOrderAdTemps) && StringUtils.isNotBlank(systemOrderAdTemps.get(0).getTgTemp())){
                req.setTemplateId(Long.parseLong(systemOrderAdTemps.get(0).getTgTemp()));
            }
        }
        if(null == req.getTemplateId()){
            List<PromotionConfigBO> selectVoList = promotionConfigMapper.queryPromotionConfigList(req.getDomainName(),req.getGoodsType(),req.getPromotionCode());
            if(CollectionUtil.isNotEmpty(selectVoList) && selectVoList.size() == 1){
                req.setTemplateId(selectVoList.stream().map(PromotionConfigBO::getTemplateId).filter(Objects::nonNull).map(Long::parseLong).findFirst().orElse(null));
            }
            if(null == req.getTemplateId()){
                Long templateId = adTempMapper.queryTemplateIdBySkuId(req.getGoodsType());
                log.info("getAdOrderAndTempConfig[] 查询广告订单和模板信息-商品模板, adTempTemplateId:{}", templateId);
                req.setTemplateId(templateId);
            }
        }
        if(null == req.getTemplateId()){
            throw new ServiceException(CterminalResultCode.H5_GOODS_TEMPLATE_NOT_EXIST);
        }
    }

    private GoodsTemplateVO getTemplateInfo(H5TempInfoReq req){
        GoodsTemplateVO templateVo = templateService.queryGoodsTemplate(req.getTemplateId());
        if(StrUtil.isBlank(templateVo.getSkuId()) || !req.getGoodsType().equals(templateVo.getSkuId())){
            throw new ServiceException(CterminalResultCode.H5_GOODS_TEMPLATE_NOT_EXIST);
        }
        return templateVo;
    }

    private H5OrderInfoVO queryOrder(String orderId) {
        if(StringUtils.isBlank(orderId)){
            return null;
        }
        SystemOrderAdTemp adTemp = adTempMapper.selectOne(Wrappers.<SystemOrderAdTemp>lambdaQuery()
                .eq(SystemOrderAdTemp::getEncryptionOrder, orderId)
                .last(ExamplesConstants.EXAM_MYSQL_LIMIT));
        if(null == adTemp){
            throw new ServiceException(CterminalResultCode.H5_ORDER_INVALID);
        }
        H5OrderInfoVO vo = adTempConverter.toH5OrderInfoVO(adTemp);
        vo.setOrderId(orderId);
        vo.setGoodsType(adTemp.getGoodsCode());
        vo.setIsLunar(adTemp.getBirthdayType());
        if(StrUtil.isNotBlank(adTemp.getExtJson())){
            OrderExtJson extJson = JSONUtil.toBean(adTemp.getExtJson(), OrderExtJson.class);
            TfGoodsCodeEnum codeEnum = TfGoodsCodeEnum.ofCodeNoisy(adTemp.getGoodsCode());
            if(TfGoodsCodeEnum.BAOBAOQIMING.equals(codeEnum)){
                vo.setIsBirth(extJson.getIsBirth());
            }else{
                vo.setBusinessType(extJson.getBusinessType());
                vo.setAreaFname(extJson.getAreaFname());
                vo.setHangyeLname(extJson.getHangyeLname());
            }
        }
        SystemOrderPayFlow payFlow = orderPayFlowMapper.selectOne(Wrappers.<SystemOrderPayFlow>lambdaQuery()
                .eq(SystemOrderPayFlow::getStatus, YesOrNoEnum.YES.getCode())
                .isNotNull(SystemOrderPayFlow::getAmount)
                .gt(SystemOrderPayFlow::getAmount, BigDecimal.ZERO)
                .eq(SystemOrderPayFlow::getAdTempId, adTemp.getId())
                .select(SystemOrderPayFlow::getMchId)
                .last(ExamplesConstants.EXAM_MYSQL_LIMIT));
        if(null != payFlow && StrUtil.isNotBlank(payFlow.getMchId())){
            vo.setMerchantNumber(payFlow.getMchId());
            vo.setAppid(tradeOnlineConfigMapper.queryMerchantAppId(adTemp.getGoodsCode(),payFlow.getMchId()));
        }
        if(StrUtil.isNotBlank(adTemp.getExtJson2())){
            vo.setPayConfigInfo(JSONUtil.toBean(adTemp.getExtJson2(),H5OrderInfoVO.PayConfigInfo.class));
        }
        return vo;
    }

    public void prePay(H5TempInfoReq req){
        if (StringUtils.isBlank(req.getOrderId()) || StringUtils.isBlank(req.getReturnUrl())){
            return;
        }
        List<String> list = Arrays.asList(PayEnum.ALI_PAY.getCode(), PayEnum.WECHAT_NATIVE.getCode(), PayEnum.ALI_PAY_NATIVE.getCode(),PayEnum.WECHAT_H5.getCode());
        for (String method : list) {
            PayReq payReq = new PayReq();
            payReq.setMethod(method);
            payReq.setOrderId(req.getOrderId());
            if (Objects.equals(PayEnum.WECHAT_H5.getCode(),method) && StringUtils.isNotBlank(req.getReturnUrlB())){
                payReq.setReturnUrl(req.getReturnUrlB());
            }else {
                payReq.setReturnUrl(req.getReturnUrl());
            }
            String key = CommonConstants.REDIS_PAY_KEY + req.getOrderId() + method;
            AsyncUtils.runAsync(()-> {
                //缓存是否存在
                if (!Boolean.TRUE.equals(redisTemplate.hasKey(key))){
                    log.info("getAdOrderAndTempConfig[] 订单预支付参数, key:{},payReq:{}", key, JSON.toJSONString(payReq));
                    CommonResult<PreOrderVO> payResult = adPayService.commonPay(payReq);
                    log.info("getAdOrderAndTempConfig[] 订单预支付结果 payResult:{}",JSON.toJSONString(payResult));
                }
                return true;
            });
        }
    }

    public Long getTemplateIdByABTestFilter(H5TempInfoReq req){
        // 不是引导页 或者从商城进来的 不走AB测试
        if(ObjectUtil.isAllNotEmpty(req.getTemplateId(),req.getOrderId())){
            return null;
        }
        if(StrUtil.hasBlank(req.getPromotionCode(), req.getDomainName(), req.getUuid(),  req.getGoodsType())) {
            return null;
        }
        // 过滤不一致的情况
        List<PromotionConfigBO> selectVoList = promotionConfigMapper.queryPromotionConfigList(req.getDomainName(),req.getGoodsType(),req.getPromotionCode());
        log.info("getTemplateIdByABTest查询推广信息, res:{}", JSON.toJSONString(selectVoList));
        if(CollectionUtil.isEmpty(selectVoList) ){
            return null;
        }

        List<ExpGroupVO> expGroupVOList = this.getTemplateIdByABTest(req,CommonConstants.TEMPLATE_AB_SCENE_CODE);
        if (CollectionUtil.isEmpty(expGroupVOList)) {
            return null;
        }
        long resultTemplateId = Long.parseLong(selectVoList.get(0).getTemplateId());
        String  expGroupParam = expGroupVOList.get(0).getExpGroupParam();
        ExpGroupParamsDTO expGroupParamsDTO = JSONObject.parseObject(expGroupParam, ExpGroupParamsDTO.class);
        if(ObjectUtil.isNotNull(expGroupParamsDTO) && StrUtil.isNotBlank(expGroupParamsDTO.getTemplateId())){
            resultTemplateId =  Long.parseLong(expGroupParamsDTO.getTemplateId());
            log.info("getTemplateIdByABTest最终返回的模板id, res:{}", resultTemplateId);
            SystemBizTemplate systemBizTemplate = systemBizTemplateMapper.selectById(resultTemplateId);
            if(ObjectUtil.isNull(systemBizTemplate) ||  !ObjectUtil.equals(systemBizTemplate.getAbTest(), NumberUtil.parseInt(CommonStatusEnum.ENABLE.getCode()))){
                return null;
            }
        }
        // 校验模板商品是否一致
        H5TempInfoReq h5TempInfoReq = new H5TempInfoReq();
        h5TempInfoReq.setTemplateId(resultTemplateId);
        h5TempInfoReq.setGoodsType(req.getGoodsType());
        getTemplateInfo(h5TempInfoReq);
        return resultTemplateId;
    }

    public List<ExpGroupVO> getTemplateIdByABTest(H5TempInfoReq req,String sceneCode){
        List<Long> expIdList = this.getExpRespVOList(req,sceneCode);
        log.info("getTemplateIdByABTest查询有效的实验id信息, res:{}", JSON.toJSONString(expIdList));
        if(CollectionUtil.isEmpty(expIdList) ){
            return null;
        }
        LibraRequestReqReq libraRequestReqReq = new LibraRequestReqReq();
        libraRequestReqReq.setSceneCode(sceneCode);
        libraRequestReqReq.setId(req.getUuid());
        libraRequestReqReq.setIdType("uid");
        libraRequestReqReq.setExpId(expIdList.get(0));
        List<ExpGroupVO> expGroupVOList = this.requestLibra(libraRequestReqReq);
        log.info("getTemplateIdByABTest查询实验对照组信息, res:{}", JSON.toJSONString(expGroupVOList));
        return expGroupVOList;
    }

    public List<Long> getExpRespVOList(H5TempInfoReq req,  String sceneCode) {
        LibraRequestReqReq libraRequestReqReq = new LibraRequestReqReq();
        libraRequestReqReq.setSceneCode(sceneCode);
        List<ExpRespVO> expRespVOSList = abTestService.libraExpPage(libraRequestReqReq);
        log.info("getExpRespVOList查询有效实验信息, expRespVOSList:{}", JSON.toJSONString(expRespVOSList));
        if(CollectionUtil.isEmpty(expRespVOSList)){
            return new ArrayList<>();
        }
        return expRespVOSList.stream()
                .filter(expRespVO -> {
                    if(StrUtil.isBlank(expRespVO.getExpParams())){
                        return true;
                    }
                    try {
                        List<ExpParamsDTO> promotionCodeIds = JSONObject.parseArray(expRespVO.getExpParams(), ExpParamsDTO.class);
                        if(CollectionUtil.isEmpty(promotionCodeIds)){
                            return true;
                        }
                        for (ExpParamsDTO promotionCodeItem : promotionCodeIds) {
                            if(StrUtil.equals(promotionCodeItem.getPromotionCode(), req.getPromotionCode())
                                    || StrUtil.equals(promotionCodeItem.getDomainName(), req.getDomainName())){
                                return true;
                            }
                        }
                    } catch (Exception e) {
                        log.info("getTemplateId解析AB的参数失败, expParams:{}", expRespVO.getExpParams(),e);
                    }
                    return false;
                })
                .map(ExpRespVO::getId)
                .collect(Collectors.toList());
    }

    public List<ExpGroupVO> requestLibra(LibraRequestReqReq req) {
        List<ExpGroupVO> result = abTestService.requestLibra(req);
        if (CollectionUtil.isEmpty(result)) {
            return Lists.newArrayList();
        }
        return result;
    }

}
